/*
 * Operation.hpp
 *
 *  Created on: 2009-9-26
 *      Author: ws
 */

#ifndef OPERATION_HPP
#define OPERATION_HPP

#include"common.hpp"
#include"Node.hpp"
#include"Operand.hpp"
class Value;
class SimdOperand;
class DataOperand;
class AddrOperand;


/*
 * the default concrete
 */

class Instruction:public Node{
	/*=======================================================
	 * 				the operand interface
	 * 		(consider : the interface may be should be contained in operation interface)
	 * ======================================================
	 */
	friend class Operand;
	friend class AddrOperand;
	friend class SimdOperand;
	friend class DataOperand;
	friend class UsageFU;
	
	protected:
		int proc_opc;
		Operand* src_opd[4];// the BW operation format have 4 source operands at most
		Operand* dest_opd[1];// the BW operation format have 1 destination operands at most
	public:
		Operand * get_src_opd(int i)
		{ assert( i < 4 && i > 0); return src_opd[i]; }
		Operand * get_dest_opd(int i = 0)
		{ assert( i ==  0); return dest_opd[i];}
	protected:
		Instruction(unsigned int flag,
					Operand * dest_opd0 = NULL,
					Operand * src_opd0 = NULL,
					Operand * src_opd1 = NULL,
					Operand * src_opd2 = NULL,
					Operand * src_opd3 = NULL
					):
						Node(flag)

		{
			dest_opd[0] = dest_opd0;
			src_opd[0] = src_opd0;
			src_opd[1] = src_opd1;
			src_opd[2] = src_opd2;
			src_opd[3] = src_opd3;
			for(int i = 0; i < 4; i++)
			{
				if(src_opd[i] == NULL)
					break;
				src_opd[i]->build_value(src);
			}
			for(int i = 0; i < 1; i++)
			{
				if(dest_opd[i] == NULL)
					break;
				dest_opd[i]->build_value(dest);
				
			}
		}
		void registe_resource(enum _Function_Type ft, int time,  UsageFU * fu);
};


template<unsigned int x>
class Operation:public Instruction{
	//no special constructor for the correct template specialize
};


Instruction * Instruction_cast(Node* n);


template<>
class Operation<START_NODE> :public Node{
	friend class BlockImpl;
	std::vector<Operand *> src_opd;
public:
	Operation(const std::vector<int>& live_in );
	virtual int get_id()const
	{
		return 0;
	}
	virtual ~Operation()
	{
		;
	}
};

Operation<START_NODE> * StartNode_cast(Node *n);

template<>
class Operation<END_NODE>:public Node{
	friend class BlockImpl;
	std::vector<Operand*> dest_opd;
public:
	Operation(const std::vector<int>& live_out );
	virtual int get_id()const
	{
		return -1;
	}
	virtual ~Operation()
	{

	}
	void AR_for_end_node(Reg_Manager * reg_manager);
};
Operation<END_NODE>* EndNode_cast(Node* n);


template< >
class Operation<SIMD_STORE>:public Instruction{
public:
	Operation(int proc_opc, SimdOperand * data0, AddrOperand * addr0, AddrOperand* addr1, AddrOperand *addr2):
		Instruction(SIMD_STORE, NULL, data0, addr0, addr1, addr2)
	{
		this->proc_opc = proc_opc;
	}
	//come from super class;
	void simd_register_allocate(Reg_Manager * regmanager);
	virtual ~Operation()
	{
		;
	}
};

Operation<SIMD_STORE> * SIMDStore_cast(Node* n);


template<>
class Operation<SIMD_LOAD>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc , SimdOperand * data0, AddrOperand * addr0, AddrOperand* addr1, AddrOperand *addr2):
		Instruction(SIMD_LOAD, data0, addr0, addr1, addr2)
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{

	}
};

Operation<SIMD_LOAD>* SIMDLoad_cast(Node *n);


template<>
class Operation<SIMD_MATH>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc , SimdOperand * dest0, SimdOperand* src0, SimdOperand *src1): Instruction(SIMD_LOAD, dest0, src0, src1)
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{

	}
};

Operation<SIMD_MATH> * SIMDMath_cast(Node *n);


template<>
class Operation<NORMAL_OPER>:public Instruction{
public:
	friend class BlockImpl;
	virtual ~Operation()
	{
	}
	Operation(int proc_opc , DataOperand* dest0, DataOperand * src0, DataOperand *src1 ): Instruction(NORMAL_OPER, dest0, src0, src1)
	{
		this->proc_opc = proc_opc;
	}
};

Operation<NORMAL_OPER> * Normal_cast(Node* n);

/*====================================================
 * 	load store operation
 *=================================================
 */
template<>
class Operation<LOAD> :public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, DataOperand * dest0, AddrOperand * src0, AddrOperand* src1, AddrOperand* src2):
							Instruction(NORMAL_OPER, dest0, src0, src1, src2)
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{

	}
};

Operation<LOAD> * Load_cast(Node*n );

template<>
class Operation<STORE>:public Instruction{
public:
	friend class BlockImpl;
	Operation( int proc_opc, DataOperand * src0, AddrOperand* src1, AddrOperand* src2, AddrOperand* src3 ):
						Instruction(STORE, NULL, src0, src1, src2, src3) 
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{

	}
};

Operation<STORE>* Store_cast(Instruction*);
/*
 * =======================================================
 *
 *	branch operation
 * =======================================================
 */
template<>
class Operation<BR_OPER>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, DataOperand *src0, DataOperand *src1, DataOperand * src2):
				Instruction(BR_OPER, NULL, src0, src1, src2)
	{
		this->proc_opc = proc_opc;
	}
	//dataflow analysis 
	//live variable 
	void build_implict_value(const std::vector<int> & v );
	void build_ctrflow();
	virtual ~Operation()
	{

	}
};
Operation<BR_OPER> * Branch_cast(Node* n);

/*=================================================
 * for subroutine call and return instruction
 *=================================================
 */

template<>
class Operation<JSR> :public Instruction{
public:
	friend class BlockImp;
	Operation(int proc_opc, DataOperand * src0): Instruction(JSR, NULL, src0)
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{

	}
};
Operation<JSR> * Jsr_cast(Node* n);

template<>
class Operation<JSR_SR>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, DataOperand* src0):Instruction(JSR, NULL, src0)
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{

	}
 };
Operation<JSR_SR> * Jsr_sr_cast(Node* n);


template<>
class Operation<RTS>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, DataOperand* src0):Instruction(RTS, NULL, src0)
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{

	}
};

Operation<RTS> * Rts_cast(Node * n);

/*
 * for Address matchmatic instruction
 */
template<>
class Operation<ADDR_OPER> :public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, AddrOperand * dest0, AddrOperand* src0, AddrOperand* src1):Instruction(ADDR_OPER, dest0,src0,src1)
	{
		this->proc_opc = proc_opc;
	} 
	virtual ~Operation()
	{

	}
 };


Operation<ADDR_OPER>* Addr_cast(Node* n);
/*
 * the instruction for communication between AGU and cluster
 */
template<>
class Operation<ADDR_DATA>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, DataOperand* dest0, AddrOperand* src0): Instruction(ADDR_DATA, dest0, src0)
	{
		this->proc_opc = proc_opc;
	}
 };

Operation<ADDR_DATA>* ADDR_DATA_cast(Node * n);

template<>
class Operation<DATA_ADDR>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, AddrOperand* dest0, DataOperand* src0):Instruction(ADDR_DATA, dest0, src0)
	{ 
		this->proc_opc = proc_opc;
	}	
};


Operation<DATA_ADDR>* DATA_ADDR_cast(Node *n );


/*
 * for  function pointer register
 * Subroutine pointer register
 */
template<>
class Operation<DATA_SR>:public Instruction{
public:
	friend class BlockImpl;
	Operation(int proc_opc, DataOperand* dest0, DataOperand* src0 ):Instruction(DATA_SR, dest0, src0)
	{
		this->proc_opc = proc_opc;
	}
	virtual ~Operation()
	{
	}
};

Operation<DATA_SR> * DATA_SR_cast(Node* n);


template<>
class Operation<SPILL | STORE> :public Instruction{
public:
	friend class BlockImpl;
	Operation<SPILL |STORE>(int offset, int id);
	virtual ~Operation()
	{

	}
};


template<>
class Operation<SPILL |LOAD>:public Instruction{
	friend class BlockImpl;
public:
	Operation<SPILL|LOAD> (int spill_offset, int id);
	virtual ~Operation()
	{

	}
};

#endif /* LCODENODE_HPP_ */
